// 定义形状类
class RectShpe {
  static tag = "rect";
  constructor({
    startX = 0,
    startY = 0,
    endX = 200,
    endY = 100,
    text = "Text",
    font = "16px serif",
    textColor = "#000",
    strokeColor = "#000",
    fillColor = "#fff",
  }) {
    this.startX = startX;
    this.startY = startY;
    this.endX = endX;
    this.endY = endY;
    this.text = text;
    this.font = font;
    this.textColor = textColor;
    this.strokeColor = strokeColor;
    this.fillColor = fillColor;
    this.shape = "rect";
    this.render = this.draw;
  }
  get width() {
    return this.endX - this.startX;
  }
  get height() {
    return this.endY - this.startY;
  }

  get vertices() {
    return [
      { x: this.startX, y: this.startY },
      { x: this.startX, y: this.endY },
      { x: this.endX, y: this.endY },
      { x: this.endX, y: this.startY },
    ];
  }
  // 判断是否为同一个点
  isSamePoint(target, point) {
    return target.x === point.x && target.y === point.y;
  }
  // 获取拉伸方向
  stretchDirection(target) {
    let direction = -1;
    let cursor = "";
    const directions = {
      0: "nw-resize",
      1: "ne-resize",
      2: "nw-resize",
      3: "ne-resize",
    };
    this.vertices.forEach((point, index) => {
      if (this.isSamePoint(target, point)) {
        direction = index;
        cursor = directions[index];
      }
    });
    return { cursor, direction };
  }

  // 根据拉伸方向，改变图形坐标
  stretch({ direction, stretchPoint }) {
    const { x, y } = stretchPoint;
    switch (direction) {
      case 0:
        // 判断边界
        if (x > this.endX || y > this.endY) {
          break;
        }
        this.startX = x;
        this.startY = y;
        break;
      case 1:
        // 判断边界
        if (x > this.endX || y < this.startY) {
          break;
        }
        this.startX = x;
        this.endY = y;
        break;
      case 2:
        // 判断边界
        if (x < this.startX || y < this.startY) {
          break;
        }
        this.endX = x;
        this.endY = y;
        break;
      case 3:
        // 判断边界
        if (x < this.startX || y > this.endY) {
          break;
        }
        this.endX = x;
        this.startY = y;
        break;
    }
    return {
      startX: this.startX,
      startY: this.startY,
      endX: this.endX,
      endY: this.endY,
    };
  }

  get renderVertices() {
    const gap = Math.min(this.width, this.height) / 5;
    console.log(gap);
    return [
      { x: this.startX, y: this.startY + gap },
      { x: this.startX, y: this.endY - gap },
      { x: this.startX + gap, y: this.endY },
      { x: this.endX - gap, y: this.endY },
      { x: this.endX, y: this.endY - gap },
      { x: this.endX, y: this.startY + gap },
      { x: this.endX - gap, y: this.startY },
      { x: this.startX + gap, y: this.startY },
    ];
  }
  pre(ctx) {
    this.draw(ctx);
    ctx.beginPath();
    ctx.moveTo(this.startX, this.startY);
    ctx.setLineDash([5, 5]);
    ctx.strokeStyle = "blue";
    ctx.strokeRect(this.startX, this.startY, this.width, this.height);
    ctx.closePath();
    this.vertices.forEach((point) => {
      ctx.beginPath();
      ctx.arc(point.x, point.y, 5, 0, Math.PI * 2, false);
      ctx.fillStyle = "red";
      ctx.fill();
      ctx.closePath();
    });
  }

  draw(ctx) {
    console.log("draw rect");
    const path = new Path2D();
    const points = this.renderVertices;
    const gap = Math.min(this.width, this.height) / 5;
    console.log("gap", gap);
    const radius = Math.sqrt(gap * gap * 2) / 2;
    console.log("radius", radius);
    ctx.beginPath();
    ctx.setLineDash([0, 0]);
    path.moveTo(points[0].x, points[0].y);
    path.lineTo(points[1].x, points[1].y);
    path.arcTo(this.startX, this.endY, points[2].x, points[2].y, radius);
    path.lineTo(points[3].x, points[3].y);
    path.arcTo(this.endX, this.endY, points[4].x, points[4].y, radius);
    path.lineTo(points[5].x, points[5].y);
    path.arcTo(this.endX, this.startY, points[6].x, points[6].y, radius);
    path.lineTo(points[7].x, points[7].y);
    path.arcTo(this.startX, this.startY, points[0].x, points[0].y, radius);
    path.lineTo(points[0].x, points[0].y);
    ctx.fillStyle = this.fillColor;
    ctx.fill(path);
    ctx.strokeStyle = this.strokeColor;
    ctx.stroke(path);
    ctx.closePath();
    if (this.text.trim() !== "") {
      ctx.beginPath();
      ctx.font = this.font;
      ctx.fillStyle = this.textColor;
      drawCenteredWrappedText(
        ctx,
        this.text,
        this.startX + this.width / 2,
        this.startY + this.height / 2 + 16,
        this.width,
        16
      );
      ctx.closePath();
    }
  }
  move(dx, dy) {
    this.startX += dx;
    this.startY += dy;
    this.endX += dx;
    this.endY += dy;
  }
  isInside(x, y) {
    return this.startX < x && x < this.endX && this.startY < y && y < this.endY;
  }
}
class CircleShpe {
  static tag = "circle";
  constructor({
    startX = 50,
    startY = 50,
    endX = 80,
    endY = 80,
    text = "Text",
    font = "16px serif",
    textColor = "#000",
    strokeColor = "#000",
    fillColor = "#fff",
  }) {
    this.startX = startX;
    this.startY = startY;
    this.endX = endX;
    this.endY = endY;
    this.text = text;
    this.font = font;
    this.textColor = textColor;
    this.strokeColor = strokeColor;
    this.fillColor = fillColor;
    this.shape = "circle";
    this.render = this.draw;
  }
  get width() {
    return this.radius * 2;
  }
  get radius() {
    const x = this.endX - this.startX;
    const y = this.endY - this.startY;
    return Math.sqrt(x * x + y * y) / 2;
  }
  get insertTextWidth() {
    return (this.endX - this.startX) * 2;
  }

  get vertices() {
    return [
      { x: this.startX - this.radius, y: this.startY - this.radius },
      { x: this.startX - this.radius, y: this.startY + this.radius },
      { x: this.startX + this.radius, y: this.startY + this.radius },
      { x: this.startX + this.radius, y: this.startY - this.radius },
    ];
  }

  // 判断是否为同一个点
  isSamePoint(target, point) {
    return target.x === point.x && target.y === point.y;
  }
  // 获取拉伸方向
  stretchDirection(target) {
    let direction = -1;
    let cursor = "";
    const directions = {
      0: "nw-resize",
      1: "ne-resize",
      2: "nw-resize",
      3: "ne-resize",
    };
    this.vertices.forEach((point, index) => {
      if (this.isSamePoint(target, point)) {
        direction = index;
        cursor = directions[index];
      }
    });
    return { cursor, direction };
  }

  // 根据拉伸方向，改变图形坐标
  stretch({ direction, stretchPoint }) {
    const { x, y } = stretchPoint;
    switch (direction) {
      case 0:
        // 判断边界
        if (x > this.vertices[2].x || y > this.vertices[2].y) {
          break;
        }
        this.endX = this.startX + (this.startX - x);
        this.endY = this.startY + (this.startY - y);
        break;
      case 1:
        // 判断边界
        if (x > this.vertices[2].x || y < this.vertices[0].y) {
          break;
        }
        this.endX = this.startX + (this.startX - x);
        this.endY = y;
        break;
      case 2:
        // 判断边界
        if (x < this.vertices[0].x || y < this.vertices[0].y) {
          break;
        }
        this.endX = x;
        this.endY = y;
        break;
      case 3:
        // 判断边界
        if (x < this.vertices[0].x || y > this.vertices[2].y) {
          break;
        }
        this.endX = x;
        this.endY = this.startY + (this.startY - y);
        break;
    }
    return {
      startX: this.startX,
      startY: this.startY,
      endX: this.endX,
      endY: this.endY,
    };
  }

  pre(ctx) {
    this.draw(ctx);
    ctx.beginPath();
    ctx.moveTo(this.startX, this.startY);
    ctx.setLineDash([5, 5]);
    ctx.strokeStyle = "blue";
    ctx.strokeRect(
      this.startX - this.radius,
      this.startY - this.radius,
      this.width,
      this.width
    );
    ctx.closePath();
    this.vertices.forEach((point) => {
      ctx.beginPath();
      ctx.arc(point.x, point.y, 5, 0, Math.PI * 2, false);
      ctx.fillStyle = "red";
      ctx.fill();
      ctx.closePath();
    });
  }

  draw(ctx) {
    console.log("draw circle");
    ctx.beginPath();
    ctx.setLineDash([0, 0]);
    ctx.arc(this.startX, this.startY, this.radius, 0, Math.PI * 2, false);
    ctx.strokeStyle = this.strokeColor;
    ctx.stroke();
    ctx.fillStyle = this.fillColor;
    ctx.fill();
    ctx.closePath();
    if (this.text.trim() !== "") {
      ctx.beginPath();
      ctx.font = this.font;
      ctx.fillStyle = this.textColor;
      drawCenteredWrappedText(
        ctx,
        this.text,
        this.startX,
        this.startY + 16,
        this.insertTextWidth,
        16
      );
      ctx.closePath();
    }
  }
  move(dx, dy) {
    this.startX += dx;
    this.startY += dy;
    this.endX += dx;
    this.endY += dy;
  }
  isInside(x, y) {
    return (
      this.vertices[0].x < x &&
      x < this.vertices[2].x &&
      this.vertices[0].y < y &&
      y < this.vertices[2].y
    );
  }
}
class LineShpe {
  static tag = "line";
  constructor({
    startX = 10,
    startY = 10,
    endX = 10,
    endY = 200,
    textColor = "#000",
    strokeColor = "#000",
    fillColor = "#000",
  }) {
    this.startX = startX;
    this.startY = startY;
    this.endX = endX;
    this.endY = endY;
    this.textColor = textColor;
    this.strokeColor = strokeColor;
    this.fillColor = fillColor;
    this.shape = "line";
    this.direction = "none";
    this.render = this.draw;
  }
  get vertices() {
    return [
      { x: this.startX, y: this.startY },
      { x: this.endX, y: this.endY },
    ];
  }
  // 判断是否为同一个点
  isSamePoint(target, point) {
    return target.x === point.x && target.y === point.y;
  }
  // 获取拉伸方向
  stretchDirection(target) {
    let direction = "none";
    const cursor = "default";
    if (this.isSamePoint(target, { x: this.startX, y: this.startY })) {
      console.log('原点')
      // 起始点不做处理
      return { cursor, direction };
    }
    // 处理垂直点
    if (target.x === this.startX) {
      console.log('垂直')
      direction = target.y > this.startY ? "down" : "up";
      this.direction = direction;
      return { cursor, direction };
    }
    const gapx = Math.abs(target.x - this.startX);
    const gapy = Math.abs(target.y - this.startY);
    console.log('大小', gapx > gapy)
    if (gapx > gapy) {
      direction = target.x > this.startX ? "right" :'left';
    } else {
      direction = target.y > this.startY ? "down" : "up";
    } 
    return { cursor, direction };
  }

  // 根据拉伸方向，改变图形坐标
  stretch({ direction, stretchPoint }) {
    const { x, y } = stretchPoint;
    if (direction === "none") {
      this.startX = x;
      this.startY = y;
    } else {
      this.endX = x;
      this.endY = y;
    }
    return {
      startX: this.startX,
      startY: this.startY,
      endX: this.endX,
      endY: this.endY,
    };
  }

  pre(ctx) {
    this.draw(ctx);
    ctx.beginPath();
    ctx.setLineDash([5, 5]);
    ctx.strokeStyle = "blue";
    // console.log("pre_direction", this.direction);
    switch (this.direction) {
      case "right":
        ctx.moveTo(this.startX, this.startY);
        ctx.lineTo(this.endX + 50, this.startY);
        break;
      case "down":
        ctx.moveTo(this.startX, this.startY);
        ctx.lineTo(this.startX, this.endY + 50);
        break;
      case "left":
        ctx.moveTo(this.startX, this.startY);
        ctx.lineTo(this.endX - 50, this.startY);
        break;
      case "up":
        ctx.moveTo(this.startX, this.startY);
        ctx.lineTo(this.startX, this.endY - 50);
        break;
      default:
        break;
    }
    ctx.stroke();
    ctx.closePath();
    // console.log('vertices',this.vertices)
    this.vertices.forEach((point) => {
      ctx.beginPath();
      ctx.arc(point.x, point.y, 5, 0, Math.PI * 2, false);
      ctx.fillStyle = "red";
      ctx.fill();
      ctx.closePath();
    });
  }

  draw(ctx) {
    // console.log("draw line");
    ctx.beginPath();
    ctx.setLineDash([0, 0]);
    ctx.moveTo(this.startX, this.startY);
    ctx.lineTo(this.endX, this.endY);
    ctx.strokeStyle = this.strokeColor;
    ctx.stroke();
    ctx.closePath();
    ctx.beginPath();
    // console.log(this.endX - 10, this.calculateYCoordinate(this.endX - 10));
    ctx.fillStyle = "#000";
    const path = new Path2D();
    if (this.startX === this.endX) {
      if (this.startY === this.endY) return;
      // 垂直情况 90deg 和 270deg(-90deg)
      if (this.startY < this.endY) {
        path.moveTo(this.endX, this.endY);
        path.lineTo(this.endX + 5, this.endY - 5);
        path.moveTo(this.endX, this.endY);
        path.lineTo(this.endX - 5, this.endY - 5);
      } else {
        path.moveTo(this.endX, this.endY);
        path.lineTo(this.endX + 5, this.endY + 5);
        path.moveTo(this.endX, this.endY);
        path.lineTo(this.endX - 5, this.endY + 5);
      }
    } else {
      // 第一象限
      // 计算箭头坐标
      const point1 = this.calculateArrowPoint(30);
      const point2 = this.calculateArrowPoint(-30);
      path.moveTo(this.endX, this.endY);
      path.lineTo(point1.x, point1.y);
      path.moveTo(this.endX, this.endY);
      path.lineTo(point2.x, point2.y);
    }
    ctx.stroke(path);
    ctx.closePath();
  }
  move(dx, dy) {
    this.startX += dx;
    this.startY += dy;
    this.endX += dx;
    this.endY += dy;
  }
  get slope() {
    const x = this.endX - this.startX;
    const y = this.endY - this.startY;
    return y / x;
  }
  // 计算指向箭头坐标
  calculateArrowPoint(deg, len = 10) {
    // console.log(this.slope, "this.slope");
    // 1.将斜率转换为弧度
    const angleRadians = slopeToAngleRadians(this.slope);
    // console.log(angleRadians, "angleRadians");
    // 2.计算箭头与线的夹角
    const angleDegree = angleRadiansToAngleDegrees(angleRadians);
    // console.log(angleDegree, "angleDegree");
    const newAngleDegree = angleDegree + deg;
    // console.log(newAngleDegree, "newAngleDegree");
    const newAngleRadians = angleDegreesToAngleRadians(newAngleDegree);
    // 3.计算箭头的斜率
    const newSlope = angleRadiansToSlope(newAngleRadians);
    // 4.计算箭头的偏移量
    const distance = this.endY - this.endX * newSlope;
    // 5.计算箭头的坐标
    let arrowX = 0;
    const flag = this.endX > this.startX;
    if (newAngleDegree > 90 || newAngleDegree < -90) {
      arrowX = flag
        ? this.endX + Math.sqrt((len * len) / (1 + newSlope * newSlope))
        : this.endX - Math.sqrt((len * len) / (1 + newSlope * newSlope));
    } else {
      arrowX = flag
        ? this.endX - Math.sqrt((len * len) / (1 + newSlope * newSlope))
        : this.endX + Math.sqrt((len * len) / (1 + newSlope * newSlope));
    }

    const arrowY = arrowX * newSlope + distance;
    // console.log(arrowX, arrowY);
    return { x: arrowX, y: arrowY };
  }
  calculateYCoordinate(x2) {
    return this.startY + this.slope * (x2 - this.startX);
  }
  isInside(x, y) {
    if (this.startX === this.endX && Math.abs(this.startX - x) < 3) {
      // 垂直状态
      // console.log("垂直");
      if (this.endY < this.startY) {
        return y < this.startY && y > this.endY;
      }
      return y > this.startY && y < this.endY;
    }
    // 定义原点和另一个坐标
    const origin = { x: this.startX, y: this.startY };
    const point2 = { x: this.endX, y: this.endY };

    // 定义目标点
    const targetPoint = { x, y };

    // 计算直线方程 y = mx + b
    const m = (point2.y - origin.y) / (point2.x - origin.x); // 计算斜率
    const b = origin.y - m * origin.x; // 计算截距

    // 代入目标点计算得到的 y 值
    const yOnLine = m * targetPoint.x + b;

    // 计算目标点到直线的距离
    const distanceToLine = Math.abs(targetPoint.y - yOnLine);

    // 判断目标点是否在直线附近（假设距离小于 1）
    const isNearLine = distanceToLine < 20;

    // console.log("目标点是否在直线附近：", isNearLine);
    const flag = this.endX > this.startX;
    // 判断目标点是否在矩形内
    if (flag) {
      return isNearLine && x > this.startX && x < this.endX;
    }
    return isNearLine && x < this.startX && x > this.endX;
  }
}
class DiamondShpe {
  constructor({
    startX = 100,
    startY = 50,
    endX = 200,
    endY = 100,
    text = "Text",
    font = "16px serif",
    textColor = "#000",
    strokeColor = "#000",
    fillColor = "#fff",
  }) {
    this.startX = startX;
    this.startY = startY;
    this.endX = endX;
    this.endY = endY;
    this.text = text;
    this.font = font;
    this.textColor = textColor;
    this.strokeColor = strokeColor;
    this.fillColor = fillColor;
    this.shape = "diamond";
    this.render = this.draw;
  }
  get width() {
    return this.wgap * 2;
  }
  get wgap() {
    return this.endX - this.startX;
  }
  get hgap() {
    return this.endY - this.startY;
  }
  get vertices() {
    /* return [
      { x: this.startX, y: this.startY + this.hgap },
      { x: this.startX + this.wgap, y: this.startY },
      { x: this.startX, y: this.startY - this.hgap },
      { x: this.startX - this.wgap, y: this.startY },
    ]; */
    return [
      { x: this.startX - this.wgap, y: this.startY - this.hgap },
      { x: this.startX - this.wgap, y: this.startY + this.hgap },
      { x: this.startX + this.wgap, y: this.startY + this.hgap },
      { x: this.startX + this.wgap, y: this.startY - this.hgap },
    ];
  }
  // 判断是否为同一个点
  isSamePoint(target, point) {
    return target.x === point.x && target.y === point.y;
  }
  // 获取拉伸方向
  stretchDirection(target) {
    let direction = -1;
    let cursor = "";
    const directions = {
      0: "nw-resize",
      1: "ne-resize",
      2: "nw-resize",
      3: "ne-resize",
    };
    this.vertices.forEach((point, index) => {
      if (this.isSamePoint(target, point)) {
        direction = index;
        cursor = directions[index];
      }
    });
    return { cursor, direction };
  }

  // 根据拉伸方向，改变图形坐标
  stretch({ direction, stretchPoint }) {
    const { x, y } = stretchPoint;
    switch (direction) {
      case 0:
        // 判断边界
        if (x > this.vertices[2].x || y > this.vertices[2].y) {
          break;
        }
        this.endX = this.startX + (this.startX - x);
        this.endY = this.startY + (this.startY - y);
        break;
      case 1:
        // 判断边界
        if (x > this.vertices[2].x || y < this.vertices[0].y) {
          break;
        }
        this.endX = this.startX + (this.startX - x);
        this.endY = y;
        break;
      case 2:
        // 判断边界
        if (x < this.vertices[0].x || y < this.vertices[0].y) {
          break;
        }
        this.endX = x;
        this.endY = y;
        break;
      case 3:
        // 判断边界
        if (x < this.vertices[0].x || y > this.vertices[2].y) {
          break;
        }
        this.endX = x;
        this.endY = this.startY + (this.startY - y);
        break;
    }
    return {
      startX: this.startX,
      startY: this.startY,
      endX: this.endX,
      endY: this.endY,
    };
  }

  get insertTextWidth() {
    return getTextMaxWidth(this.vertices);
  }

  pre(ctx) {
    this.draw(ctx);
    ctx.beginPath();
    ctx.moveTo(this.startX, this.startY);
    ctx.setLineDash([5, 5]);
    ctx.strokeStyle = "blue";
    ctx.strokeRect(
      this.startX - this.wgap,
      this.startY - this.hgap,
      this.wgap * 2,
      this.hgap * 2
    );
    ctx.closePath();
    this.vertices.forEach((point) => {
      ctx.beginPath();
      ctx.arc(point.x, point.y, 5, 0, Math.PI * 2, false);
      ctx.fillStyle = "red";
      ctx.fill();
      ctx.closePath();
    });
  }
  draw(ctx) {
    console.log("draw diamond");
    const { wgap, hgap } = this;
    ctx.beginPath();
    ctx.setLineDash([0, 0]);
    ctx.moveTo(this.startX, this.startY + hgap);
    ctx.lineTo(this.startX + wgap, this.startY);
    ctx.lineTo(this.startX, this.startY - hgap);
    ctx.lineTo(this.startX - wgap, this.startY);
    ctx.lineTo(this.startX, this.startY + hgap);
    ctx.strokeStyle = this.strokeColor;
    ctx.stroke();
    ctx.fillStyle = this.fillColor;
    ctx.fill();
    ctx.closePath();
    if (this.text.trim() !== "") {
      ctx.beginPath();
      ctx.font = this.font;
      ctx.fillStyle = this.textColor;
      drawCenteredWrappedText(
        ctx,
        this.text,
        this.startX,
        this.startY + 16,
        this.insertTextWidth,
        16
      );
      ctx.closePath();
    }
  }
  move(dx, dy) {
    this.startX += dx;
    this.startY += dy;
    this.endX += dx;
    this.endY += dy;
  }
  isInside(x, y) {
    const { vertices } = this;
    let intersectCount = 0;
    for (let i = 0; i < vertices.length; i++) {
      const vertex1 = vertices[i];
      const vertex2 = vertices[(i + 1) % vertices.length]; // 获取下一个顶点，形成边
      if (
        vertex1.y > y !== vertex2.y > y &&
        x <
          ((vertex2.x - vertex1.x) * (y - vertex1.y)) /
            (vertex2.y - vertex1.y) +
            vertex1.x
      ) {
        intersectCount++;
      }
    }
    return intersectCount % 2 === 1; // 奇数个交点则在内部
  }
}

class TextShpe {
  constructor({
    startX,
    startY,
    endX,
    endY,
    text = "Text",
    font = "16px serif",
    textColor = "#000",
  }) {
    this.startX = startX;
    this.startY = startY;
    this.endX = endX;
    this.endY = endY;
    this.text = text;
    this.font = font;
    this.textColor = textColor;
    this.shape = "text";
    this.render = this.draw;
    this.select = false;
  }
  get width() {
    return this.endX - this.startX;
  }
  get height() {
    return this.endY - this.startY;
  }

  get vertices() {
    return [
      { x: this.startX, y: this.startY },
      { x: this.startX, y: this.endY },
      { x: this.endX, y: this.endY },
      { x: this.endX, y: this.startY },
    ];
  }
  // 判断是否为同一个点
  isSamePoint(target, point) {
    return target.x === point.x && target.y === point.y;
  }

  // 获取拉伸方向
  stretchDirection(target) {
    let direction = -1;
    let cursor = "";
    const directions = {
      0: "nw-resize",
      1: "ne-resize",
      2: "nw-resize",
      3: "ne-resize",
    };
    this.vertices.forEach((point, index) => {
      if (this.isSamePoint(target, point)) {
        direction = index;
        cursor = directions[index];
      }
    });
    return { cursor, direction };
  }

  // 根据拉伸方向，改变图形坐标
  stretch({ direction, stretchPoint }) {
    const { x, y } = stretchPoint;
    switch (direction) {
      case 0:
        // 判断边界
        if (x > this.endX || y > this.endY) {
          break;
        }
        this.startX = x;
        this.startY = y;
        break;
      case 1:
        // 判断边界
        if (x > this.endX || y < this.startY) {
          break;
        }
        this.startX = x;
        this.endY = y;
        break;
      case 2:
        // 判断边界
        if (x < this.startX || y < this.startY) {
          break;
        }
        this.endX = x;
        this.endY = y;
        break;
      case 3:
        // 判断边界
        if (x < this.startX || y > this.endY) {
          break;
        }
        this.endX = x;
        this.startY = y;
        break;
    }
    return {
      startX: this.startX,
      startY: this.startY,
      endX: this.endX,
      endY: this.endY,
    };
  }

  pre(ctx) {
    this.draw(ctx);
    ctx.beginPath();
    ctx.strokeStyle = "blue";
    ctx.setLineDash([15, 5]);
    ctx.strokeRect(this.startX, this.startY, this.width, this.height);
    ctx.closePath();
    this.vertices.forEach((point) => {
      ctx.beginPath();
      ctx.arc(point.x, point.y, 5, 0, Math.PI * 2, false);
      ctx.fillStyle = "red";
      ctx.fill();
      ctx.closePath();
    });
  }
  draw(ctx) {
    ctx.beginPath();
    ctx.fillStyle = '#fff'
    ctx.fillRect(this.startX, this.startY, this.width, this.height);
    ctx.closePath();
    ctx.beginPath();
    ctx.font = this.font;
    ctx.fillStyle = this.textColor;
    drawCenteredWrappedText(
      ctx,
      this.text,
      this.startX + this.width / 2,
      this.startY + this.height / 2 + 16,
      this.width,
      16
    );
    ctx.closePath();
  }
  isInside(x, y) {
    return this.startX < x && x < this.endX && this.startY < y && y < this.endY;
  }
  move(dx, dy) {
    this.startX += dx;
    this.startY += dy;
    this.endX += dx;
    this.endY += dy;
  }
}

class Shapes {
  constructor(curShape = "rect") {
    this.rect = RectShpe;
    this.circle = CircleShpe;
    this.line = LineShpe;
    this.diamond = DiamondShpe;
    this.text = TextShpe;
    this.curShape = curShape;
    this.startX = 0;
    this.startY = 0;
    this.isStart = false;
    this.isDraging = false;
    this.stretch = false;
    this.shapeList = []
    this.textList = []
    this.curIndex = -1;
  }
  get list () {
    return this.shapeList.concat(this.textList)
  }
  render(ctx) {
    // console.log(this.list)
    ctx.reset();
    for (let i = 0; i < this.list.length; i++) {
      this.list[i].render(ctx);
    }
  }
}
